#include "unp.h"


int
main() {
    int                 i, maxi, maxfd, listenfd, connfd, sockfd;
    int                 nready, client[FD_SETSIZE];
    ssize_t             n;
    fd_set              rset, allset;
    char                buf[MAXLINE];
    socklen_t           clilen;
    struct sockaddr_in  cliaddr, servaddr;

    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("openning sock stream");
        exit(1);
    }

    bzero(&servaddr, sizeof(struct sockaddr_in));
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(SERV_PORT);

    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        perror("binding stream socket");
        exit(1);
    }

    if (listen(listenfd, LISTENQ) == -1) {
        perror("listening stream socket");
        exit(1);
    }

    maxfd = listenfd;
    maxi  = -1;
    for (i = 0; i < FD_SETSIZE; ++i) {
        client[i] = -1;
    }
    FD_ZERO(&allset);
    FD_SET(listenfd, &allset);

    for ( ; ; ) {
        rset = allset;
        nready = select(maxfd+1, &rset, NULL, NULL, NULL);
        
        //先处理监听描述符
        if (FD_ISSET(listenfd, &rset)) {
            clilen = sizeof(cliaddr);
            if ((connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen)) < 0) {
                perror("accept the client socket");
                continue;
            }
            //打印客户IP
            if (inet_ntop(AF_INET, &cliaddr.sin_addr, buf, INET_ADDRSTRLEN) == NULL) {
                perror("inet_ntop");
                exit(EXIT_FAILURE);
            }
            printf("new client: %s:%d\n", buf, ntohs(cliaddr.sin_port));

            for(i = 0; i < FD_SETSIZE; ++i) 
                if (client[i] == -1) {
                    client[i] = connfd;
                    break;
                }
            if (i == FD_SETSIZE)
                err_quit("too many clients");

            FD_SET(connfd, &allset);
            if (connfd > maxfd)
                maxfd = connfd;
            if (i > maxi)
                maxi = i;
            if (--nready <= 0)
                continue;
        }

        //再处理已连接套接字
        for (i = 0; i <= maxfd; ++i) {
            if ((sockfd = client[i]) < 0)
                continue;
            if (FD_ISSET(sockfd, &rset)) {
                if ((n = read(sockfd, buf, MAXLINE)) < 0) {
                    close(sockfd);
                    client[i] =-1;
                    FD_CLR(sockfd, &allset);
                } else {
                    writen(sockfd, buf, n);
                }
            }
            if (--nready <= 0)
                break;
        }


    }

    return 0;
}
